#include "EMS_pwm_drv.h"

#define EMS_TIMER_1k_PERIOD		(1000)

#define EMS_TIMER_10k_PERIOD		(50*2)
#define EMS_TIMER_10k_DUTY		(EMS_TIMER_10k_PERIOD*6/10)

static TIM_TimeBaseInitType TIM_TimeBaseStructure;
static OCInitType TIM_OCInitStructure;
static uint16_t CCR1_Val       = 333;
static uint16_t CCR2_Val       = 249;
static uint16_t CCR3_Val       = 166;
static uint16_t CCR4_Val       = 83;
static uint16_t PrescalerValue = 0;

static int cur_period_timer_cnt = 0;
static int cur_duty_timer_cnt = 0;


/**
 * @brief  Inserts a delay time.
 * @param count specifies the delay time length.
 */
__inline static void my_delay(uint32_t count)
{
    for (; count > 0; count--)
        ;
}

/**
 * @brief  Configures the different system clocks.
 */
void ems_rcc_cfg(void)
{
    /* TIM3 clock enable */
    // RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM3, ENABLE);
    // timer 2
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM2, ENABLE);
    // timer 5
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM5, ENABLE);

    /* GPIOA and GPIOB clock enable */
    RCC_EnableAPB2PeriphClk(
        RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_GPIOB | RCC_APB2_PERIPH_GPIOC | RCC_APB2_PERIPH_AFIO, ENABLE);
}

/**
 * @brief  Configure the TIM3 Ouput Channels.
 */
void ems_gpio_cfg(void)
{
    GPIO_InitType GPIO_InitStructure;

    GPIO_InitStruct(&GPIO_InitStructure);
    /* GPIOA Configuration:TIM3 Channel1, 2, 3 and 4 as alternate function push-pull */
    // PA1 ----[TIM2_CH2 ---AF2]
    GPIO_InitStructure.Pin        = GPIO_PIN_1;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Current = GPIO_DC_4mA;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF2_TIM2;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);

    // PA2 ----[TIM5_CH3 ---AF6]
    GPIO_InitStructure.Pin        = GPIO_PIN_2;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Current = GPIO_DC_4mA;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF6_TIM5;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}

//----------ems 通道1 关闭 / 开启
void ems_playlod1_stop(void)
{
    TIM2->CCDAT2 = 0; //TIM_TimeBaseStructure.Period   TIM_OCInitStructure.Pulse  EMS_TIMER_10k_PERIOD
    TIM5->CCDAT3 = 0;
}

void ems_playlod1_restar(void)
{
    /* TIM2 enable counter */
    TIM2->CCDAT2 = TIM_OCInitStructure.Pulse;
    TIM5->CCDAT3 = TIM_OCInitStructure.Pulse;
}

void ems_playlod1_restar_with_duty(int duty)
{
  /* TIM2 enable counter */
	TIM2->CCDAT2 = TIM_TimeBaseStructure.Period *(duty)/100;
	TIM5->CCDAT3 = TIM_TimeBaseStructure.Period *(duty)/100;
}

void ems_freq_select_3khz(void)
{
  ems_output_disable();
  TIM_Enable(TIM2, DISABLE);
  TIM_Enable(TIM5, DISABLE);

  /* Compute the prescaler value */
    PrescalerValue = 64 -1 ; //(uint16_t)(SystemCoreClock / 12000000) - 1;
    // PrescalerValue =1 (uint16_t)(SystemCoreClock / 10800000) - 1;; //(uint16_t)(SystemCoreClock / 12000000) - 1;
    /* Time base configuration */
    TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);    
    TIM_TimeBaseStructure.Period    = EMS_TIMER_1k_PERIOD/3;
    TIM_TimeBaseStructure.Prescaler = PrescalerValue;
    TIM_TimeBaseStructure.ClkDiv    = 0;
    TIM_TimeBaseStructure.CntMode   = TIM_CNT_MODE_UP;

    //-------------timer 2 ch1    
    TIM_InitTimeBase(TIM2, &TIM_TimeBaseStructure);
    /* PWM1 Mode configuration: Channel1 */
    TIM_InitOcStruct(&TIM_OCInitStructure);    
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = TIM_TimeBaseStructure.Period *2 /10; //CCR1_Val;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_LOW;

    TIM_InitOc2(TIM2, &TIM_OCInitStructure);
    TIM_ConfigOc2Preload(TIM2, TIM_OC_PRE_LOAD_ENABLE);
    TIM_Enable(TIM2, ENABLE);
    //---------------timer 5 ch2

    TIM_InitTimeBase(TIM5, &TIM_TimeBaseStructure);

    /* PWM1 Mode configuration: Channel1 */
    TIM_InitOcStruct(&TIM_OCInitStructure);    
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = TIM_TimeBaseStructure.Period *2 /10; //CCR1_Val;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_LOW;

    TIM_InitOc3(TIM5, &TIM_OCInitStructure);
    TIM_ConfigOc3Preload(TIM5, TIM_OC_PRE_LOAD_ENABLE);
		my_delay(1200);
    TIM_Enable(TIM5, ENABLE);
    cur_period_timer_cnt = TIM_TimeBaseStructure.Period;
    cur_duty_timer_cnt = TIM_OCInitStructure.Pulse;
    ems_output_enable();
}


/*******
 *  ems cfg 9khz
 * 
 * ****/
void ems_freq_select_9khz(void)
{
  ems_output_disable();
  TIM_Enable(TIM2, DISABLE);
  TIM_Enable(TIM5, DISABLE);

  /* Compute the prescaler value */
    PrescalerValue = 64 -1 ; //(uint16_t)(SystemCoreClock / 12000000) - 1;
    // PrescalerValue =1 (uint16_t)(SystemCoreClock / 10800000) - 1;; //(uint16_t)(SystemCoreClock / 12000000) - 1;
    /* Time base configuration */
    TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);    
    TIM_TimeBaseStructure.Period    = EMS_TIMER_1k_PERIOD/9;
    TIM_TimeBaseStructure.Prescaler = PrescalerValue;
    TIM_TimeBaseStructure.ClkDiv    = 0;
    TIM_TimeBaseStructure.CntMode   = TIM_CNT_MODE_UP;

    //-------------timer 2 ch1    
    TIM_InitTimeBase(TIM2, &TIM_TimeBaseStructure);
    /* PWM1 Mode configuration: Channel1 */
    TIM_InitOcStruct(&TIM_OCInitStructure);    
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = TIM_TimeBaseStructure.Period *30 /100; //CCR1_Val;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_LOW;

    TIM_InitOc2(TIM2, &TIM_OCInitStructure);
    TIM_ConfigOc2Preload(TIM2, TIM_OC_PRE_LOAD_ENABLE);
    TIM_Enable(TIM2, ENABLE);
    //---------------timer 5 ch2

    TIM_InitTimeBase(TIM5, &TIM_TimeBaseStructure);

    /* PWM1 Mode configuration: Channel1 */
    TIM_InitOcStruct(&TIM_OCInitStructure);    
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = TIM_TimeBaseStructure.Period *30 /100; //CCR1_Val;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_LOW;

    TIM_InitOc3(TIM5, &TIM_OCInitStructure);
    TIM_ConfigOc3Preload(TIM5, TIM_OC_PRE_LOAD_ENABLE);
		my_delay(900*9);
    TIM_Enable(TIM5, ENABLE);
    cur_period_timer_cnt = TIM_TimeBaseStructure.Period;
    cur_duty_timer_cnt = TIM_OCInitStructure.Pulse;
    ems_output_enable();
}


/*******
 *  ems cfg 10khz
 * 
 * ****/
void ems_freq_select_12khz(void)
{
  ems_output_disable();
    TIM_Enable(TIM2, DISABLE);
  TIM_Enable(TIM5, DISABLE);

  /* Compute the prescaler value */
    PrescalerValue = 64 -1 ; //(uint16_t)(SystemCoreClock / 12000000) - 1;
    // PrescalerValue =1 (uint16_t)(SystemCoreClock / 10800000) - 1;; //(uint16_t)(SystemCoreClock / 12000000) - 1;
    /* Time base configuration */
    TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);    
    TIM_TimeBaseStructure.Period    = EMS_TIMER_1k_PERIOD/12;
    TIM_TimeBaseStructure.Prescaler = PrescalerValue;
    TIM_TimeBaseStructure.ClkDiv    = 0;
    TIM_TimeBaseStructure.CntMode   = TIM_CNT_MODE_UP;

    //-------------timer 2 ch1    
    TIM_InitTimeBase(TIM2, &TIM_TimeBaseStructure);
    /* PWM1 Mode configuration: Channel1 */
    TIM_InitOcStruct(&TIM_OCInitStructure);    
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = TIM_TimeBaseStructure.Period *30 /100; //CCR1_Val;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_LOW;

    TIM_InitOc2(TIM2, &TIM_OCInitStructure);
    TIM_ConfigOc2Preload(TIM2, TIM_OC_PRE_LOAD_ENABLE);
    TIM_Enable(TIM2, ENABLE);
    //---------------timer 5 ch2

    TIM_InitTimeBase(TIM5, &TIM_TimeBaseStructure);

    /* PWM1 Mode configuration: Channel1 */
    TIM_InitOcStruct(&TIM_OCInitStructure);    
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = TIM_TimeBaseStructure.Period *30 /100; //CCR1_Val;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_LOW;

    TIM_InitOc3(TIM5, &TIM_OCInitStructure);
    TIM_ConfigOc3Preload(TIM5, TIM_OC_PRE_LOAD_ENABLE);
		my_delay(900*11);
    TIM_Enable(TIM5, ENABLE);
    cur_period_timer_cnt = TIM_TimeBaseStructure.Period;
    cur_duty_timer_cnt = TIM_OCInitStructure.Pulse;
    ems_output_enable();
}

/*******
 *  ems cfg 15khz
 * 
 * ****/
void ems_freq_select_15khz(void)
{
  ems_output_disable();
  TIM_Enable(TIM2, DISABLE);
  TIM_Enable(TIM5, DISABLE);

  /* Compute the prescaler value */
    PrescalerValue = 64 -1 ; //(uint16_t)(SystemCoreClock / 12000000) - 1;
    // PrescalerValue =1 (uint16_t)(SystemCoreClock / 10800000) - 1;; //(uint16_t)(SystemCoreClock / 12000000) - 1;
    /* Time base configuration */
    TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);    
    TIM_TimeBaseStructure.Period    = EMS_TIMER_1k_PERIOD/15 - 1;
    TIM_TimeBaseStructure.Prescaler = PrescalerValue;
    TIM_TimeBaseStructure.ClkDiv    = 0;
    TIM_TimeBaseStructure.CntMode   = TIM_CNT_MODE_UP;

    //-------------timer 2 ch1    
    TIM_InitTimeBase(TIM2, &TIM_TimeBaseStructure);
    /* PWM1 Mode configuration: Channel1 */
    TIM_InitOcStruct(&TIM_OCInitStructure);    
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = TIM_TimeBaseStructure.Period *30 /100; //CCR1_Val;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_LOW;

    TIM_InitOc2(TIM2, &TIM_OCInitStructure);
    TIM_ConfigOc2Preload(TIM2, TIM_OC_PRE_LOAD_ENABLE);
    TIM_Enable(TIM2, ENABLE);
    //---------------timer 5 ch2

    TIM_InitTimeBase(TIM5, &TIM_TimeBaseStructure);

    /* PWM1 Mode configuration: Channel1 */
    TIM_InitOcStruct(&TIM_OCInitStructure);    
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = TIM_TimeBaseStructure.Period *30 /100; //CCR1_Val;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_LOW;

    TIM_InitOc3(TIM5, &TIM_OCInitStructure);
    TIM_ConfigOc3Preload(TIM5, TIM_OC_PRE_LOAD_ENABLE);
		my_delay(200 + 100);  //200
    TIM_Enable(TIM5, ENABLE);
    cur_period_timer_cnt = TIM_TimeBaseStructure.Period;
    cur_duty_timer_cnt = TIM_OCInitStructure.Pulse;
    ems_output_enable();
}



void ems_freq_select_1hz(void)
{
    ems_output_disable();
	  TIM_Enable(TIM2, DISABLE);
		TIM_Enable(TIM5, DISABLE);

  /* Compute the prescaler value */
    PrescalerValue = 40000; //(uint16_t)(SystemCoreClock / 12000000) - 1;
    // PrescalerValue =1 (uint16_t)(SystemCoreClock / 10800000) - 1;; //(uint16_t)(SystemCoreClock / 12000000) - 1;
    /* Time base configuration */
    TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);    
    TIM_TimeBaseStructure.Period    = EMS_TIMER_10k_PERIOD;
    TIM_TimeBaseStructure.Prescaler = PrescalerValue;
    TIM_TimeBaseStructure.ClkDiv    = 0;
    TIM_TimeBaseStructure.CntMode   = TIM_CNT_MODE_UP;

    //-------------timer 2 ch1    
    TIM_InitTimeBase(TIM2, &TIM_TimeBaseStructure);
    /* PWM1 Mode configuration: Channel1 */
    TIM_InitOcStruct(&TIM_OCInitStructure);    
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = EMS_TIMER_10k_DUTY; //CCR1_Val;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_HIGH;

    TIM_InitOc2(TIM2, &TIM_OCInitStructure);
    TIM_ConfigOc2Preload(TIM2, TIM_OC_PRE_LOAD_ENABLE);
    TIM_Enable(TIM2, ENABLE);
    //---------------timer 5 ch2

    TIM_InitTimeBase(TIM5, &TIM_TimeBaseStructure);

    /* PWM1 Mode configuration: Channel1 */
    TIM_InitOcStruct(&TIM_OCInitStructure);    
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = EMS_TIMER_10k_DUTY; //CCR1_Val;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_HIGH;

    TIM_InitOc3(TIM5, &TIM_OCInitStructure);
    TIM_ConfigOc3Preload(TIM5, TIM_OC_PRE_LOAD_ENABLE);
		my_delay(11000000/2);
    TIM_Enable(TIM5, ENABLE);
    ems_output_enable();
}

void ems_freq_select_4khz(void)
{
    ems_output_disable();
	  TIM_Enable(TIM2, DISABLE);
		TIM_Enable(TIM5, DISABLE);

  /* Compute the prescaler value */
    PrescalerValue = 10; //(uint16_t)(SystemCoreClock / 12000000) - 1;
    // PrescalerValue =1 (uint16_t)(SystemCoreClock / 10800000) - 1;; //(uint16_t)(SystemCoreClock / 12000000) - 1;
    /* Time base configuration */
    TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);    
    TIM_TimeBaseStructure.Period    = EMS_TIMER_10k_PERIOD;
    TIM_TimeBaseStructure.Prescaler = PrescalerValue;
    TIM_TimeBaseStructure.ClkDiv    = 0;
    TIM_TimeBaseStructure.CntMode   = TIM_CNT_MODE_UP;

    //-------------timer 2 ch1    
    TIM_InitTimeBase(TIM2, &TIM_TimeBaseStructure);
    /* PWM1 Mode configuration: Channel1 */
    TIM_InitOcStruct(&TIM_OCInitStructure);    
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = EMS_TIMER_10k_DUTY; //CCR1_Val;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_HIGH;

    TIM_InitOc2(TIM2, &TIM_OCInitStructure);
    TIM_ConfigOc2Preload(TIM2, TIM_OC_PRE_LOAD_ENABLE);
    TIM_Enable(TIM2, ENABLE);
    //---------------timer 5 ch2

    TIM_InitTimeBase(TIM5, &TIM_TimeBaseStructure);

    /* PWM1 Mode configuration: Channel1 */
    TIM_InitOcStruct(&TIM_OCInitStructure);    
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = EMS_TIMER_10k_DUTY; //CCR1_Val;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_HIGH;

    TIM_InitOc3(TIM5, &TIM_OCInitStructure);
    TIM_ConfigOc3Preload(TIM5, TIM_OC_PRE_LOAD_ENABLE);
		my_delay(11000/4);
    TIM_Enable(TIM5, ENABLE);
    ems_output_enable();
}

void ems_freq_select_2khz(void)
{
    ems_output_disable();
	  TIM_Enable(TIM2, DISABLE);
		TIM_Enable(TIM5, DISABLE);

  /* Compute the prescaler value */
    PrescalerValue = 20; //(uint16_t)(SystemCoreClock / 12000000) - 1;
    // PrescalerValue =1 (uint16_t)(SystemCoreClock / 10800000) - 1;; //(uint16_t)(SystemCoreClock / 12000000) - 1;
    /* Time base configuration */
    TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);    
    TIM_TimeBaseStructure.Period    = EMS_TIMER_10k_PERIOD;
    TIM_TimeBaseStructure.Prescaler = PrescalerValue;
    TIM_TimeBaseStructure.ClkDiv    = 0;
    TIM_TimeBaseStructure.CntMode   = TIM_CNT_MODE_UP;

    //-------------timer 2 ch1    
    TIM_InitTimeBase(TIM2, &TIM_TimeBaseStructure);
    /* PWM1 Mode configuration: Channel1 */
    TIM_InitOcStruct(&TIM_OCInitStructure);    
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = EMS_TIMER_10k_DUTY; //CCR1_Val;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_HIGH;

    TIM_InitOc2(TIM2, &TIM_OCInitStructure);
    TIM_ConfigOc2Preload(TIM2, TIM_OC_PRE_LOAD_ENABLE);
    TIM_Enable(TIM2, ENABLE);
    //---------------timer 5 ch2

    TIM_InitTimeBase(TIM5, &TIM_TimeBaseStructure);

    /* PWM1 Mode configuration: Channel1 */
    TIM_InitOcStruct(&TIM_OCInitStructure);    
    TIM_OCInitStructure.OcMode      = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = EMS_TIMER_10k_DUTY; //CCR1_Val;
    TIM_OCInitStructure.OcPolarity  = TIM_OC_POLARITY_HIGH;

    TIM_InitOc3(TIM5, &TIM_OCInitStructure);
    TIM_ConfigOc2Preload(TIM5, TIM_OC_PRE_LOAD_ENABLE);
		my_delay(11000/2);
    TIM_Enable(TIM5, ENABLE);
    ems_output_enable();
}

/*******
 *  ems 频率20khz， 占空比25%
 * 
 * ****/

void my_ems_init(void)
{
  ems_rcc_cfg();
  ems_gpio_cfg();
  ems_freq_select_3khz();
}
